/* Scan Example

   This example code is in the Public Domain (or CC0 licensed, at your option.)

   Unless required by applicable law or agreed to in writing, this
   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
   CONDITIONS OF ANY KIND, either express or implied.
*/

/*
    This example shows how to scan for available set of APs.
*/
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/event_groups.h"
#include "esp_wifi.h"
#include "esp_log.h"
#include "esp_event.h"
#include "scan.h"
#include "sdkconfig.h"

static wifi_ap_record_t *ap_records = 0;
static char *ssidStr = 0;
static const char *TAG = "scan";

static void print_auth_mode(int authmode)
{
    switch (authmode)
    {
        case WIFI_AUTH_OPEN:
            ESP_LOGI(TAG, "Authmode \tWIFI_AUTH_OPEN");
            break;
        case WIFI_AUTH_WEP:
            ESP_LOGI(TAG, "Authmode \tWIFI_AUTH_WEP");
            break;
        case WIFI_AUTH_WPA_PSK:
            ESP_LOGI(TAG, "Authmode \tWIFI_AUTH_WPA_PSK");
            break;
        case WIFI_AUTH_WPA2_PSK:
            ESP_LOGI(TAG, "Authmode \tWIFI_AUTH_WPA2_PSK");
            break;
        case WIFI_AUTH_WPA_WPA2_PSK:
            ESP_LOGI(TAG, "Authmode \tWIFI_AUTH_WPA_WPA2_PSK");
            break;
        case WIFI_AUTH_WPA2_ENTERPRISE:
            ESP_LOGI(TAG, "Authmode \tWIFI_AUTH_WPA2_ENTERPRISE");
            break;
        case WIFI_AUTH_WPA3_PSK:
            ESP_LOGI(TAG, "Authmode \tWIFI_AUTH_WPA3_PSK");
            break;
        case WIFI_AUTH_WPA2_WPA3_PSK:
            ESP_LOGI(TAG, "Authmode \tWIFI_AUTH_WPA2_WPA3_PSK");
            break;
        default:
            ESP_LOGI(TAG, "Authmode \tWIFI_AUTH_UNKNOWN");
            break;
    }
}

static void print_cipher_type(int pairwise_cipher, int group_cipher)
{
    switch (pairwise_cipher)
    {
        case WIFI_CIPHER_TYPE_NONE:
            ESP_LOGI(TAG, "Pairwise Cipher \tWIFI_CIPHER_TYPE_NONE");
            break;
        case WIFI_CIPHER_TYPE_WEP40:
            ESP_LOGI(TAG, "Pairwise Cipher \tWIFI_CIPHER_TYPE_WEP40");
            break;
        case WIFI_CIPHER_TYPE_WEP104:
            ESP_LOGI(TAG, "Pairwise Cipher \tWIFI_CIPHER_TYPE_WEP104");
            break;
        case WIFI_CIPHER_TYPE_TKIP:
            ESP_LOGI(TAG, "Pairwise Cipher \tWIFI_CIPHER_TYPE_TKIP");
            break;
        case WIFI_CIPHER_TYPE_CCMP:
            ESP_LOGI(TAG, "Pairwise Cipher \tWIFI_CIPHER_TYPE_CCMP");
            break;
        case WIFI_CIPHER_TYPE_TKIP_CCMP:
            ESP_LOGI(TAG, "Pairwise Cipher \tWIFI_CIPHER_TYPE_TKIP_CCMP");
            break;
        default:
            ESP_LOGI(TAG, "Pairwise Cipher \tWIFI_CIPHER_TYPE_UNKNOWN");
            break;
    }

    switch (group_cipher)
    {
        case WIFI_CIPHER_TYPE_NONE:
            ESP_LOGI(TAG, "Group Cipher \tWIFI_CIPHER_TYPE_NONE");
            break;
        case WIFI_CIPHER_TYPE_WEP40:
            ESP_LOGI(TAG, "Group Cipher \tWIFI_CIPHER_TYPE_WEP40");
            break;
        case WIFI_CIPHER_TYPE_WEP104:
            ESP_LOGI(TAG, "Group Cipher \tWIFI_CIPHER_TYPE_WEP104");
            break;
        case WIFI_CIPHER_TYPE_TKIP:
            ESP_LOGI(TAG, "Group Cipher \tWIFI_CIPHER_TYPE_TKIP");
            break;
        case WIFI_CIPHER_TYPE_CCMP:
            ESP_LOGI(TAG, "Group Cipher \tWIFI_CIPHER_TYPE_CCMP");
            break;
        case WIFI_CIPHER_TYPE_TKIP_CCMP:
            ESP_LOGI(TAG, "Group Cipher \tWIFI_CIPHER_TYPE_TKIP_CCMP");
            break;
        default:
            ESP_LOGI(TAG, "Group Cipher \tWIFI_CIPHER_TYPE_UNKNOWN");
            break;
    }
}

/* Initialize Wi-Fi as sta and set scan method */
int wifi_scan(void (*scan_done)(char *ssid))
{
    int len = 0;
    uint16_t ap_num = 0;
    ESP_LOGI(TAG, "START scan");
    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
    ESP_ERROR_CHECK(esp_wifi_start());
    // esp_err_t ret = esp_wifi_scan_start(NULL, true);
    // ESP_LOGI(TAG, "ret = %d", ret);
    if (esp_wifi_scan_start(NULL, true) != ESP_OK) // 这在连接wifi就关闭连接重新扫描
    {
        esp_wifi_disconnect();
        ESP_LOGI(TAG,"scan disconnect");
        esp_wifi_scan_start(NULL, true);
    }

    ESP_ERROR_CHECK(esp_wifi_scan_get_ap_num(&ap_num));
    if (ap_num == 0)
    {
        // 如果没有可用 Wi-Fi 热点，输出提示信息
        ESP_LOGI(TAG, "No AP found");
        return 1;
    }
    if (ap_records)
    {
        free(ap_records);
        ap_records = NULL;
    }
    if (ssidStr)
    {
        free(ssidStr);
        ssidStr = NULL;
    }

    ap_records = (wifi_ap_record_t *)malloc(sizeof(wifi_ap_record_t) * ap_num);
    if (!ap_records)
    {
        ESP_LOGE(TAG, "malloc error");
        return 2;
    }
    ESP_ERROR_CHECK(esp_wifi_scan_get_ap_records(&ap_num, ap_records));
    ESP_LOGI(TAG, "Total APs scanned = %u", ap_num);

    for (int i = 0;  i < ap_num; i++)
    {
        len += strlen((char *)ap_records[i].ssid) + 1;
    }

    ssidStr = (char *)malloc(len);
    if (ssidStr == NULL)
    {
        return 3;
    }

    len = 0;
    for (int i = 0;  i < ap_num; i++)
    {
        strcpy(ssidStr + len, (char *)ap_records[i].ssid);
        len += strlen((char *)ap_records[i].ssid) + 1;
        ssidStr[len - 1] = '\n';
    }
    ssidStr[len - 1] = '\0';

    if (scan_done)
    {
        scan_done(ssidStr);
    }

    return 0;

}

void wifi_scan_stop(void)
{
    esp_wifi_scan_stop();
    // if (ap_records)
    // {
    //     free(ap_records);
    //     ap_records = NULL;
    // }
    // if (ssidStr)
    // {
    //     free(ssidStr);
    //     ssidStr = NULL;
    // }
    esp_wifi_connect();
}

/**
 * @brief 获取wifi扫描结果
 * 
 * @param i 
 * @return char* 
 */
char* wifi_get_scan_result(int i)
{
    return (char*)ap_records[i].ssid;
}
